"use strict"

/**
 * @拉曼的一维卷积神经网络处理模型
 */

/**
 * @库导入
 */
// 导入tfjs和tfvis和库
import * as tf from "@tensorflow/tfjs"


/**
 * @建立模型
 * Hebbian Principle：神经网络中越接近输入的层的网络应该越稀疏
 */
export function createCnnModel() {

  /**
   * @输入层
   * 输入数据为[1600]
   * 为实现cnn1d，需要转为[1600, 1]
   */
  const inputSymbolTensor = tf.input({
    name: "input",
    // 输入空间的形状，不需要加batchSize的null
    shape: [1600],
  })

  /**
   * @变形层
   * 输入数据为[1600]，为实现cnn1d，需要转为[1600, 1]
   */
  const reshapeSymbolTensor = tf.layers.reshape({
    name: "reshape",
    // 输出空间的形状
    targetShape: [1600, 1],
  // 构建层间逻辑：输入层 => 变形层
  }).apply(inputSymbolTensor)


  /**
   * @平均池化层
   * 3个平行的平均池化
   *   1600 => 800
   *   1600 => 320
   *   1600 => 80
   */

  // 平均池化层-A
  const avePoolongSymbolTensorA = tf.layers.averagePooling1d({
    name: "ave-pooling-a",
    // 池化尺寸
    poolSize: [2],
    // 池化步长
    strides: [2],
    // 边缘处理方法，valid为不添加填充，same为填充
    padding: "valid",
  // 构建层间逻辑：变形层 => 平均池化层-A
  }).apply(reshapeSymbolTensor)

  // 平均池化层-B
  const avePoolongSymbolTensorB = tf.layers.averagePooling1d({
    name: "ave-pooling-b",
    // 池化尺寸
    poolSize: [5],
    // 池化步长
    strides: [5],
    // 边缘处理方法，valid为不添加填充，same为填充
    padding: "valid",
  // 构建层间逻辑：变形层 => 平均池化层-B
  }).apply(reshapeSymbolTensor)

  // 平均池化层-C
  const avePoolongSymbolTensorC = tf.layers.averagePooling1d({
    name: "ave-pooling-c",
    // 池化尺寸
    poolSize: [20],
    // 池化步长
    strides: [20],
    // 边缘处理方法，valid为不添加填充，same为填充
    padding: "valid",
  // 构建层间逻辑：变形层 => 平均池化层-C
  }).apply(reshapeSymbolTensor)

  /**
   * @卷积层
   * 需要共享同一个卷积层实例
   */

  // 实例
  const convSharedLayer = tf.layers.conv1d({
    name: "conv-shared",
    // 滤波器数量，即输出的最后一层channels数量
    filters: 8,
    // 卷积核尺寸
    kernelSize: [5],
    // 卷积步长
    strides: [5],
    // 边缘处理方法，valid为不添加填充，same为填充
    padding: "same",
    // 不启用偏置
    useBias: false,
    // 不使用激活函数
    activation: undefined,
  })

  // 卷积层-A、卷积层-B、卷积层-C
  const convSymbolTensorA = convSharedLayer.apply(avePoolongSymbolTensorA)
  const convSymbolTensorB = convSharedLayer.apply(avePoolongSymbolTensorB)
  const convSymbolTensorC = convSharedLayer.apply(avePoolongSymbolTensorC)

  /**
   * @合并层
   * 合并卷积结果
   */
  const concSymbolTensor =  tf.layers.concatenate({
    name: "concatenate",
    // 沿着哪个轴进行连接，默认为-1，即最后一个轴（需注意batch轴为0轴）
    axis: 1
  }).apply([convSymbolTensorA, convSymbolTensorB, convSymbolTensorC])

  /**
   * @扁平化层
   */
  const flattenSymbolTensor = tf.layers.flatten({
    name: "cnn-flatten",
  }).apply(concSymbolTensor)

  /**
   * @全连接层
   */
  const denseSymbolTensor = tf.layers.dense({
    name: "cnn-dense-1",
    // 输出空间的维度
    units: 2,
    // 启用偏差
    useBias: true,
    // 无激活函数
    activation: undefined,
  }).apply(flattenSymbolTensor)

  /**
   * @建立模型
   */
  const model = tf.model({
    name: "cnn-model",
    // 输入张量
    inputs: inputSymbolTensor,
    // 输出张量
    outputs: denseSymbolTensor
  })

  model.summary()

  // 返回模型
  return model
}

